package com.msi;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.log4j.Logger;

/**
 * Generator grafów zgodnych z treścą zadania
 * 
 * @author Michał Kołodziejski
 */
public class GraphGenerator {

	/**
	 * Logger
	 */
	private static Logger logger = Logger.getLogger(GraphGenerator.class);

	/**
	 * Generuje graf zgodny z treścią zadania
	 * 
	 * @param n
	 *            ilość węzłów grafu
	 * @param r
	 *            parametr
	 * @return graf w postaci macierzy sąsiedztwa
	 */
	public static Graph generateGraph(int n, double r) {
		// pusty graf
		Graph graph = Graph
				.createGraphByNeighbourMatrix(new ArrayList<List<Integer>>());

		List<Vertex> vertices = new ArrayList<Vertex>();

		Random rnd = new Random();
		Map<Integer, Point2D> coordMap = new HashMap<Integer, Point2D>();
		for (int i = 0; i < n; ++i) {
			Vertex v = new Vertex(i);
			/*
			 * double x = (rnd.nextDouble() - 0.5) * 5; double y =
			 * (rnd.nextDouble() - 0.5) * 5;
			 */
			double x = rnd.nextDouble();
			double y = rnd.nextDouble();
			v.setX(x);
			v.setY(y);
			vertices.add(v);
			coordMap.put(i, new Point2D.Double(x * 200, y * 200));
		}
		graph.setCoordinates(coordMap);

		// wygenerowanie wszystkich liczb losowych ograniczenie ich przedziału
		int randomNumbersVectorLength = (n * (n - 1)) / 2;
		List<Double> randomNumbersVector = new ArrayList<Double>(
				randomNumbersVectorLength);
		double max = -1000000, min = 1000000;
		for (int i = 0; i < randomNumbersVectorLength; ++i) {
			double randomNumber = rnd.nextGaussian();
			// logger.debug(randomNumber);

			if (randomNumber < min) {
				min = randomNumber;
			} else if (randomNumber > max) {
				max = randomNumber;
			}
			randomNumbersVector.add(new Double(randomNumber));
		}
		// logger.debug("min = "+min);
		// logger.debug("max = "+max);
		// ograniczenie przedziału wygenerowanych liczb
		double width = (Math.abs(min) + Math.abs(max));
		double minAbs = Math.abs(min);
		for (int i = 0; i < randomNumbersVectorLength; ++i) {
			double number = randomNumbersVector.get(i).doubleValue();
			number += minAbs;
			number /= width;
			// logger.debug(number);
			randomNumbersVector.set(i, new Double(number));
		}

		// ustalenie sąsiedztwa między wierzchołkami grafu
		Iterator<Double> it = randomNumbersVector.iterator();
		for (int i = 0; i < n - 1; ++i) {
			for (int j = i + 1; j < n; ++j) {
				Vertex v1 = vertices.get(i);
				Vertex v2 = vertices.get(j);

				double x = it.next();
				double distance = Math.sqrt(Math.pow(v1.getX() - v2.getX(), 2)
						+ Math.pow(v1.getY() - v2.getY(), 2));
				double exp = Math.exp(-r * distance);
				logger.debug("x = " + x + ", exp = " + exp + ", distance = "
						+ distance);
				if (x < exp) {
					logger.debug("dodana krawędź [v1: " + v1.getId() + ", v2: "
							+ v2.getId() + "]");
					v1.addNeighbour(v2);
				}
			}
		}

		// dodanie wierzchołków do grafu
		Map<Integer, Vertex> map = new HashMap<Integer, Vertex>();
		for (int i = 0; i < n; ++i) {
			map.put(i, vertices.get(i));
		}
		graph.setVertices(map);

		return graph;
	}
}
